from scipy.stats import chi2_contingency
import pandas as pd
from sklearn.ensemble import IsolationForest
import matplotlib.pyplot as plt
from outliers import smirnov_grubbs as grubbs
import schedule
import time


# 流量监控分配
def check_traffic_balance(df, group_col='group', expected_ratio=0.5):
    """卡方检验流量分配是否均衡"""
    observed = df[group_col].value_counts().values
    expected = [expected_ratio * len(df), (1 - expected_ratio) * len(df)]
    _, p, _, _ = chi2_contingency([observed, expected])
    if p < 0.05:
        print(f"警告：流量分配不均（p={p:.4f}），请检查分组逻辑！")
    return p


# 核心指标异常检测
def detect_metric_anomalies(df, metric_col='ctr', date_col='date', threshold=3):
    """检测指标突变的两种方法"""
    # 方法1：Z-Score（同一实验组内）
    df['z_score'] = df.groupby('group')[metric_col].transform(
        lambda x: (x - x.mean()) / x.std()
    )
    z_anomalies = df[df['z_score'].abs() > threshold]

    # 方法2：日环比突降（跨实验组）
    df['prev_day'] = df.groupby('group')[metric_col].shift(1)
    df['day_change'] = (df[metric_col] - df['prev_day']) / df['prev_day']
    change_anomalies = df[df['day_change'].abs() > 0.5]  # 日环比超50%

    return pd.concat([z_anomalies, change_anomalies])


def detect_behavior_anomalies(df, features=['click_count', 'session_duration']):
    """无监督检测异常用户行为模式"""
    model = IsolationForest(contamination=0.05, random_state=42)
    df['anomaly_score'] = model.fit_predict(df[features])
    anomalies = df[df['anomaly_score'] == -1]

    # 可视化异常点分布
    plt.scatter(df[features[0]], df[features[1]], c=df['anomaly_score'], cmap='coolwarm')
    plt.xlabel(features[0])
    plt.ylabel(features[1])
    plt.title('用户行为异常检测')
    plt.show()

    return anomalies


def check_pvalue_outliers(p_values, alpha=0.05):
    """检测显著性p值的异常波动"""
    outliers = grubbs.max_test_outliers(p_values, alpha=alpha)
    if len(outliers) > 0:
        print(f"警告：异常p值{outliers}，可能因数据污染或流量突变导致")


def daily_monitor():
    # 从数据库获取最新AB测试数据
    df = pd.read_sql("SELECT * FROM ab_test WHERE date=CURDATE()", con=db_conn)

    # 执行所有检测模块
    check_traffic_balance(df)
    metric_anomalies = detect_metric_anomalies(df)
    behavior_anomalies = detect_behavior_anomalies(df)

    # 发送报警邮件
    if not metric_anomalies.empty:
        send_alert_email(metric_anomalies.to_html())


# 每天9点自动运行
schedule.every().day.at("09:00").do(daily_monitor)
while True:
    schedule.run_pending()
    time.sleep(60)
